package wviz.index;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;

import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermPositions;

import wviz.gui.T2vPanel;

/**
 * Produce a set of word pairs ordered by their cooccurence in the index *
 * 
 * @author Laurie
 */

public class Cooc {

	private final int numberOfPairs;

	private final double MIN_DISTANCE = 0.01d;

	private final double DECAY = 0.9d;

	private IndexReader ir;
	private Term[] highFreqTerms;
	private Positions[] termPositions;

	public Cooc(Term[] terms, IndexReader ird, int numbPairs)
			throws IOException {
		ir = ird;
		this.numberOfPairs = numbPairs;
		highFreqTerms = terms;
		termPositions = new Positions[highFreqTerms.length];
		for (int y = 0; y < this.highFreqTerms.length; y++) {
			if (ir.termPositions(highFreqTerms[y]) == null) {
				System.err.println("error null");
				break;
			}

			termPositions[y] = makePositions(ir.termPositions(highFreqTerms[y]));
		}
	}

	public List<String[]> getWordPairsForGraph() throws IOException {

		TwoWordsInfo twi = null;

		// to store info about two words and their relatedness
		Map<String, TwoWordsInfo> wordPairMap = new HashMap<String, TwoWordsInfo>();

		TwoWordsSet wordPairSet = new TwoWordsSet();

		Positions tp0, tp1;

		System.out.println("selecttermarrarysize = " + highFreqTerms.length);

		for (int x = 0; x < highFreqTerms.length; x++) {
			for (int y = x + 1; y < highFreqTerms.length; y++) {

				tp0 = termPositions[x];

				for (int doc0 : tp0.getDocIds()) {

					tp1 = termPositions[y];

					for (int doc1 : tp1.getDocIds()) {
						if (doc0 != doc1) {
							System.out.println("docs NOT ewqual  ");
							continue;
						}

						final int[] tpv0 = tp0.getPositions(doc0);
						final int[] tpv1 = tp1.getPositions(doc1);

						TwoWords wordPair = wordPairSet.extract(
								highFreqTerms[x].text(),
								highFreqTerms[y].text());

						final double closeness = getCooccurValueFromPositionVectors(
								tpv0, tpv1);

						final String word0 = wordPair.getWord1();

						final String word1 = wordPair.getWord2();

						// cooccurences of two words stored in map. Unique key
						// is string of two words concatenated.
						if (closeness > MIN_DISTANCE) {
							final String key = word0 + word1;

							if (wordPairMap.containsKey(key)) {
								twi = (TwoWordsInfo) wordPairMap.get(key);
								twi.addClose(closeness);

							} else {
								wordPairMap.put(key, new TwoWordsInfo(word0,
										word1, closeness));
							}
						}
					}
				}
			}
		}

		// info about the relationship between two words in order of closeness
		Queue<TwoWordsInfo> jpq = new PriorityQueue<TwoWordsInfo>(
				wordPairMap.values());

		int count = 0;

		// the list of pairs to output for graph building
		List<String[]> pairList = new ArrayList<String[]>(numberOfPairs);

		while (!jpq.isEmpty() && count < numberOfPairs) {
			twi = (TwoWordsInfo) jpq.poll();

			pairList.add(new String[] { twi.getWord0(), twi.getWord1() });

			if (count < 10) {
				System.out.println("word0: " + twi.getWord0() + " word1: "
						+ twi.getWord1() + " closeness: " + twi.getDistance());
			}
			count++;
		}

		System.out.println("pair list size " + pairList.size());
		return pairList;
	}

	/**
	 * closeness value indicating cooccurence of the two words based on position
	 * vectors
	 */
	private final double getCooccurValueFromPositionVectors(final int[] w0,
			final int[] w1) {

		final int MAX_DISTANCE = T2vPanel.maxWordDistance;

		double cooccur = 0.0d;

		for (int p = 0; p < w0.length; p++) {

			for (int q = 0; q < w1.length; q++) {

				final int pqDistance = Math.abs(w0[p] - w1[q]);

				if (pqDistance <= MAX_DISTANCE)
					cooccur = cooccur + Math.pow(DECAY, pqDistance);
			}
		}
		return cooccur;
	}

	private Positions makePositions(TermPositions tp) throws IOException {
		Positions pos = new Positions();

		while (tp.next()) {
			int docId = tp.doc();
			int[] tpv = new int[tp.freq()];

			for (int i = 0; i < tpv.length; i++) {
				tpv[i] = tp.nextPosition();
			}
			pos.add(docId, tpv);
		}
		return pos;
	}
}
